using JGSY.CourseManagement.Infrastructure.Messaging;
using Microsoft.Extensions.Logging;
using System.Windows;

/// <summary>
/// 提供基于Prism区域的导航服务实现，支持视图注册和异步导航
/// </summary>
namespace JGSY.CourseManagement.Presentation.Navigation
{
    public class NavigationService : INavigationService
    {
        private readonly IRegionManager _regionManager;
        private readonly ILogger<NavigationService> _logger;
        private readonly IMessageBus _messageBus;
        private readonly string _defaultRegionName;
        private readonly Dictionary<string, Type> _viewRegistry = new Dictionary<string, Type>();
        private string _currentView;
        private string _previousView;

        public event EventHandler<NavigationEventArgs> Navigated;
        public event EventHandler<NavigationEventArgs> NavigationFailed;

        bool INavigationService.CanGoBack => CanGoBack();

        public NavigationService(IRegionManager regionManager, ILogger<NavigationService> logger, IMessageBus messageBus, string defaultRegionName = "MainRegion")
        {
            _regionManager = regionManager ?? throw new ArgumentNullException(nameof(regionManager));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            _messageBus = messageBus ?? throw new ArgumentNullException(nameof(messageBus));
            _defaultRegionName = defaultRegionName;
        }

        public void RegisterView(string viewName, Type viewType)
        {
            if (string.IsNullOrWhiteSpace(viewName))
                throw new ArgumentException("视图名称不能为空", nameof(viewName));
            if (viewType == null)
                throw new ArgumentNullException(nameof(viewType));
            if (!typeof(FrameworkElement).IsAssignableFrom(viewType))
                throw new ArgumentException("视图类型必须继承自FrameworkElement", nameof(viewType));

            _viewRegistry[viewName] = viewType;
            _logger.LogInformation("已注册视图: {ViewName} -> {ViewType}", viewName, viewType.FullName);
        }

        public async Task NavigateAsync(string viewName, NavigationParameters parameters = null)
        {
            if (string.IsNullOrWhiteSpace(viewName))
                throw new ArgumentException("View name cannot be null or whitespace", nameof(viewName));

            try
            {
                _logger.LogInformation("Navigating to view: {ViewName}", viewName);
                _previousView = _currentView;
                _currentView = viewName;

                if (!_regionManager.Regions.ContainsRegionWithName(_defaultRegionName))
                {
                    _logger.LogError("Region {RegionName} not found for navigation", _defaultRegionName);
                    throw new InvalidOperationException($"Region {_defaultRegionName} not registered");
                }
                var region = _regionManager.Regions[_defaultRegionName];

                if (!_viewRegistry.TryGetValue(viewName, out var viewType))
                {
                    _logger.LogError("未找到注册的视图: {ViewName}", viewName);
                    throw new KeyNotFoundException($"视图 {viewName} 未注册");
                }

                var tcs = new TaskCompletionSource<NavigationResult>();

                try
                {
                    // 使用Success属性判断导航结果
                    region.RequestNavigate(
                        new Uri(viewType.Name, UriKind.Relative),
                        navigationResult =>
                        {
                            if (navigationResult.Success)
                            {
                                _logger.LogInformation("Navigation to view {ViewName} succeeded", viewType.Name);
                                tcs.SetResult(navigationResult);
                            }
                            else
                            {
                                var errorMessage = $"Navigation to view {viewType.Name} failed: {navigationResult.Exception?.Message ?? "No error message"}";
                                _logger.LogError(navigationResult.Exception, errorMessage);
                                tcs.SetException(new InvalidOperationException(errorMessage, navigationResult.Exception));
                            }
                        },
                        parameters ?? new NavigationParameters()
                    );

                    await tcs.Task;
                    _logger.LogInformation("Successfully navigated to view: {ViewName}", viewName);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Unexpected error during navigation to view {ViewName}", viewType.Name);
                    throw;
                }

                // Publish navigation changed message
                await _messageBus.PublishAsync(new NavigationChangedMessage
                {
                    PreviousView = _previousView,
                    CurrentView = _currentView,
                    Timestamp = DateTime.UtcNow
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to navigate to view: {ViewName}", viewName);
                NavigationFailed?.Invoke(this, new NavigationEventArgs(viewName, parameters, ex));
                throw;
            }
        }

        /// <summary>
        /// 异步导航到指定视图
        /// </summary>
        /// <param name="viewName">要导航到的视图名称</param>
        /// <returns>表示异步导航操作的任务</returns>
        /// <exception cref="ArgumentException">当视图名称为空或空白时抛出</exception>
        public async Task NavigateToAsync(string viewName)
        {
            await NavigateAsync(viewName, null);
        }

        public bool CanGoBack()
        {
            return !string.IsNullOrWhiteSpace(_previousView);
        }

        public async Task GoBackAsync(NavigationParameters parameters = null)
        {
            if (!CanGoBack())
            {
                _logger.LogWarning("No previous view to navigate back to");
                return;
            }

            var tempView = _previousView;
            _previousView = _currentView;
            _currentView = tempView;

            await NavigateAsync(tempView, parameters);
        }

        public void ConfigureRegionManager(string regionName, object regionTarget)
        {
            if (string.IsNullOrWhiteSpace(regionName))
                throw new ArgumentException("Region name cannot be null or whitespace", nameof(regionName));

            if (regionTarget == null)
                throw new ArgumentNullException(nameof(regionTarget));

            if (!_regionManager.Regions.ContainsRegionWithName(regionName))
            {
                _regionManager.RegisterViewWithRegion(regionName, () => regionTarget);
                _logger.LogInformation("Configured region manager for region: {RegionName}", regionName);
            }
        }

        public bool NavigateTo(string viewName, object parameter = null, bool cache = false)
        {
            try
            {
                NavigateAsync(viewName, parameter as NavigationParameters).Wait();
                Navigated?.Invoke(this, new NavigationEventArgs(viewName, parameter, null));
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to navigate to view: {ViewName}", viewName);
                NavigationFailed?.Invoke(this, new NavigationEventArgs(viewName, parameter, ex));
                return false;
            }
        }

        public bool GoBack()
        {
            try
            {
                GoBackAsync().Wait();
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to navigate back");
                return false;
            }
        }

        public void ClearHistory()
        {
            _previousView = null;
            _logger.LogInformation("Navigation history cleared");
        }

    }

    public class NavigationChangedMessage
    {
        public string PreviousView { get; set; }
        public string CurrentView { get; set; }
        public DateTime Timestamp { get; set; }
    }
}